/**
 * HT1621 液晶屏驱动
 * Copyright (c) 2021 深圳市智辰科技有限公司
 * All rights reserved.
 */

#include "nonos.h"
#include "ht1621.h"

// 指令 ID
#define ID_CMD		0x04 // 0b100
#define ID_WRITE	0x05 // 0b101

// 默认延时
#define TCLK() mcu_delay_us(10)
// GPIO 操作
#define CS(x) (dev->cs(x))
#define WR(x) (dev->wr(x))
#define RD(x) (dev->rd(x))
#define DW(x) (dev->dw(x))
#define DR()  (dev->dr())

void ht1621_init(driver_ht1621_t *dev, FUNC_GPIO_Out cs, FUNC_GPIO_Out wr, FUNC_GPIO_Out rd, FUNC_GPIO_Out dw, FUNC_GPIO_ReadIn dr) {
	dev->cs = cs;
	dev->wr = wr;
	dev->rd = rd;
	dev->dw = dw;
	dev->dr = dr;
}

// 发送命令前，初始化总线
static void _bus_init(const driver_ht1621_t *dev) {
	CS(1); WR(1); DW(1); TCLK();
	CS(0); TCLK();
}

// 总线通信结束
static void _bus_end(const driver_ht1621_t *dev) {
	CS(1); WR(1); DW(1);
}

// 写一个 bit
static void _wbit(const driver_ht1621_t *dev, uint8_t bit) {
	WR(0); DW(bit); TCLK(); 
	WR(1); TCLK();
}

// 写多个 bit (从最高有效位开始发送)
// @param nbits: > 0 时，表示从高位开始发送；< 0 时，表示从低位开始发送
static void _wbits(const driver_ht1621_t *dev, uint16_t bits, int nbits) {
	uint8_t bit;

	if(nbits > 0) {
		for(int i = nbits-1; i >= 0; i--) {
			bit = (bits >> i) & 0x01;
			_wbit(dev, bit);
		}
	} else {
		nbits = -nbits;
		for(int i = 0; i <= nbits-1; i++) {
			bit = (bits >> i) & 0x01;
			_wbit(dev, bit);
		}
	}
}

void ht1621_cmd(const driver_ht1621_t *dev, const uint8_t cmds[], int len) {
	// 发送命令前，初始化总线
	_bus_init(dev);	
	// 发送命令模式 100 (3 bits)
	_wbits(dev, ID_CMD, 3);
	
	uint16_t cmd;
	for(int i = 0; i < len; i++) {
		// 发送命令字 (9 bits)，最低位补 0
		cmd = cmds[i] << 1;
		_wbits(dev, cmd, 9);
	}
	
	// 结束
	_bus_end(dev);
}

void ht1621_write(const driver_ht1621_t *dev, uint8_t addr, const uint8_t data[], int len) {
	// 发送命令前，初始化总线
	_bus_init(dev);	
	// 发送写数据指令 101 (3 bits)
	_wbits(dev, ID_WRITE, 3);
	// 发送地址 (6 bits)
	_wbits(dev, addr, 6);

	uint16_t dat;
	for(int i = 0; i < len; i++) {
		dat = data[i];
		// 发送数据 (4 bits，数据是从低位开始发送)
		_wbits(dev, dat, -4);
	}
	
	// 结束
	_bus_end(dev);
}
